﻿using CKS.PLC.Core.Event;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

using ZR.Model.Models.ProductionControl;

namespace CKS.PLC.Core
{
    /// <summary>
    /// 设为静态类 
    /// 主要功能是提取方法和热重载
    /// </summary>
    public static class PlcActionDLLManage
    {
        private static readonly object _lockDll = new object();
        private static Type ActionBaseType = null;
        public static string _lastFileHash;
        static string DllName = "CKS.PLC.Action.dll";
        static Assembly assembly = null;
        static FileSystemWatcher watcher = null;
        public static void RegisterPlcActionDLL()
        {
            WatchAndReload(DllName);
        }

        /// <summary>
        /// 监视指定的DLL文件，并在文件变更时重新加载程序集
        /// </summary>
        /// <param name="dllPath"></param>
        private static void WatchAndReload(string dllPath)
        {
            var dllFullPath = Path.Combine(Directory.GetCurrentDirectory(), dllPath);

            ReloadAssembly(dllFullPath);

            watcher = new FileSystemWatcher();
            watcher.Path = Path.GetDirectoryName(dllFullPath);
            watcher.Filter = Path.GetFileName(dllFullPath);
            watcher.NotifyFilter = NotifyFilters.LastWrite;
            watcher.Changed += (sender, e) =>
            {
                // 延迟一段时间以确保文件写入完成
                Thread.Sleep(1000);
                ReloadAssembly(dllPath);
            };
            watcher.Created += (sender, e) =>
            {
                ReloadAssembly(dllPath);
            };

            watcher.EnableRaisingEvents = true;
        }

        /// <summary>
        /// 重新加载指定的DLL文件，并更新ActionBaseType类型
        /// </summary>
        /// <param name="dllPath"></param>
        private static void ReloadAssembly(string dllPath)
        {
            lock (_lockDll)
            {

                // 加载程序集
                // assembly = _currentLoadContext.LoadFromAssemblyPath(dllPath);
                try
                {
                    byte[] assemblyBytes = File.ReadAllBytes(dllPath);
                    string currentHash = CalculateFileHash(assemblyBytes);
                    if (currentHash == _lastFileHash)
                    {
                        // 文件内容未变化，忽略事件
                        return;
                    }
                    _lastFileHash = currentHash;
                    EventBus.AddLogInfoToQueues($"加载了CKS.PLC.Action.dll");
                    
                    // using var stream = new MemoryStream(assemblyBytes);
                    assembly = Assembly.Load(assemblyBytes);//AssemblyLoadContext.Default.LoadFromStream(stream);
                    string typeName = "CKS.PLC.Action.PLCAction";
                    ActionBaseType = assembly.GetType(typeName);

                    MethodInfo method = ActionBaseType.GetMethod("ShowVersion");
                    method.Invoke(null, null);

                }
                catch (Exception)
                {

                }
            }
        }

        /// <summary>
        /// 获取PLC动作的基类类型
        /// </summary>
        /// <returns></returns>
        public static Type GetActionBaseType()
        {
            lock (_lockDll)
            {
                return ActionBaseType;
            }
        }

        /// <summary>
        /// 获取当前加载的PLC动作程序集
        /// </summary>
        /// <returns></returns>
        public static Assembly GetActionAssembly() { 
            return assembly;
        }

        /// <summary>
        /// 计算文件的SHA256哈希值
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        private static string CalculateFileHash(byte[] bytes)
        {
            using (var sha256 = SHA256.Create())
            {
                byte[] hashBytes = sha256.ComputeHash(bytes);
                return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
            }
        }
    }
}
